/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */
package info.peigen.hotpot.component.open.api.core.service.base;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import info.peigen.hotpot.common.core.result.ListResult;
import info.peigen.hotpot.common.core.result.PageResult;
import info.peigen.hotpot.common.core.result.ResultBase;
import info.peigen.hotpot.common.core.result.SingleResult;
import info.peigen.hotpot.common.service.base.*;
import info.peigen.hotpot.common.service.base.event.LogEventHandler;
import info.peigen.hotpot.common.service.base.event.ServiceOrderLogEvent;
import info.peigen.hotpot.common.service.base.event.ServiceResultLogEvent;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContext;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContextThreadLocal;
import info.peigen.hotpot.component.open.api.core.config.OpenApiAuthVerifyIgnoreConfiguration;
import info.peigen.hotpot.component.open.api.core.service.processor.base.OpenApiProcessorServiceInvoke;
import info.peigen.hotpot.component.open.api.core.service.processor.base.post.OpenApiPostLogEventProcessor;
import info.peigen.hotpot.component.open.api.core.service.processor.base.pre.*;
import info.peigen.hotpot.component.open.api.core.service.processor.base.pre.callback.OpenApiCallbackCallTypeProcessor;
import info.peigen.hotpot.component.open.api.core.service.processor.base.pre.callback.OpenApiCallbackMethodTypeProcessor;
import info.peigen.hotpot.component.open.api.core.service.processor.base.pre.callback.OpenApiCallbackOrderCheckProcessor;
import info.peigen.hotpot.component.open.api.core.service.processor.base.pre.simple.OpenApiFillOrderEncryptProcessor;
import info.peigen.hotpot.component.open.api.facade.order.OpenApiOrder;
import info.peigen.hotpot.component.open.api.facade.processor.base.OpenApiProcessor;
import info.peigen.hotpot.component.open.api.facade.processor.base.OpenApiProcessorServiceContext;
import info.peigen.hotpot.component.open.api.facade.result.OpenListResult;
import info.peigen.hotpot.component.open.api.facade.result.OpenPageResult;
import info.peigen.hotpot.component.open.api.facade.result.OpenSingleResult;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;
import org.noear.solon.data.annotation.TranAnno;
import org.noear.solon.data.tran.TranPolicy;
import org.noear.solon.data.tran.TranUtils;

import java.util.List;
import java.util.stream.Collectors;

import static org.noear.solon.data.tran.TranIsolation.read_committed;

/**
 * <b>(AbstractOpenApiProcessorService)</b>
 * 所有服务层的抽象类,提供最基础的流程支撑
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2019/05/19
 */
@Slf4j
@SuppressWarnings("ALL")
@FieldDefaults(level = AccessLevel.PROTECTED)
public abstract class AbstractOpenApiProcessorService implements ServiceFacade {
    @Inject
    ProfileConfig                         profileConfig;
    @Inject
    LogEventHandler                       logEventHandler;
    @Inject
    AppContext                            context;
    @Inject
    OpenApiPreLogEventProcessor           openApiPreLogEventProcessor;
    @Inject
    OpenApiFillOrderEncryptProcessor      openApiFillOrderEncryptProcessor;
    @Inject
    OpenApiCallbackOrderCheckProcessor    openApiCallbackOrderCheckProcessor;
    @Inject
    OpenApiCallbackMethodTypeProcessor    openApiCallbackMethodTypeProcessor;
    @Inject
    OpenApiCallbackCallTypeProcessor      openApiCallbackCallTypeProcessor;
    // @Inject
    // OpenApiCallbackBusinessTypeProcessor  openApiCallbackBusinessTypeProcessor;
    @Inject
    OpenApiCheckOrderProcessor            openApiCheckOrderProcessor;
    @Inject
    OpenApiPostLogEventProcessor          openApiPostLogEventProcessor;
    @Inject
    OpenApiDecryptProcessor               openApiDecryptProcessor;
    @Inject
    OpenApiRequestNoUniqueVerifyProcessor openApiRequestNoUniqueVerifyProcessor;
    @Inject
    OpenApiAuthVerifyProcessor            openApiAuthVerifyProcessor;
    @Inject
    OpenApiFacadeExecuteProcessor         openApiFacadeExecuteProcessor;
    // @Inject
    // OpenApiSessionVerifyProcessor         openApiSessionVerifyProcessor;
    @Inject
    OpenApiAuthVerifyIgnoreConfiguration  openApiAuthVerifyIgnoreConfiguration;
    @Inject
    OpenApiSignatureProcessor             openApiSignatureProcessor;
    @Inject
    OpenSimpleApiProcessor                openSimpleApiProcessor;

    /**
     * 领域模型的命令模式执行器
     *
     * @param serviceContext 上下文
     * @param invoke         接口
     */
    public void execute(OpenApiProcessorServiceContext<OpenApiOrder, OpenSingleResult> serviceContext, OpenApiProcessorServiceInvoke invoke) {
        try {
            // 1. 增加预处理器
            serviceContext.addProcessors(openApiPreLogEventProcessor, openApiCheckOrderProcessor,
                    openApiSignatureProcessor, openApiAuthVerifyProcessor, openApiRequestNoUniqueVerifyProcessor,
                    openApiDecryptProcessor, openApiFacadeExecuteProcessor);
            invoke.addPreProcessor(serviceContext);
            // 2. 增加业务处理器
            invoke.addProcessor(serviceContext);
            // 3. 增加后处理器
            invoke.addPostProcessor(serviceContext);
            serviceContext.addProcessors(openApiPostLogEventProcessor);

            // 4. Mock处理器替换
            if (profileConfig.isMock()) {
                if (ObjectUtil.isNull(ServiceTestMockContextThreadLocal.currentContext())) {
                    new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().build());
                }

                // 4.1 获取全部继承于Process的处理器
                List<OpenApiProcessor> beans = context.getBeansOfType(OpenApiProcessor.class);

                // 将被替换的Mock处理器 列表
                List<OpenApiProcessor> mockProcessors = Lists.newArrayList();
                // 将被移除的处理器 列表
                List<String> removeProcessorName = Lists.newArrayList();

                // 4.2 获取当前使用的处理器
                List<OpenApiProcessor> processors = serviceContext.getProcessors();
                processors.forEach(processor -> {
                    String processorName = processor.getClass().getSimpleName();
                    beans.stream()
                            // 4.2.1 过滤出包含Mock名的处理器
                            .filter(bean -> bean.getClass().getSimpleName().contains("Mock"))
                            // 4.2.2 把包含Mock名的处理器取出
                            .filter(bean -> bean.getClass().getSimpleName().replaceAll("Mock", "")
                                    .equalsIgnoreCase(processorName)).findAny().ifPresent(bean -> {
                                // 填充需要替换的Mock处理器
                                mockProcessors.add(bean);
                                // 填充需要移除的处理器
                                removeProcessorName.add(processorName);
                            });
                });

                // 4.3 从当前使用的处理器中剔除可被Mock替换的处理器
                processors.removeIf(processor -> CollUtil.contains(removeProcessorName, processor.getClass()
                        .getSimpleName()));
                if (CollUtil.isNotEmpty(mockProcessors)) {
                    serviceContext.addProcessors(mockProcessors.toArray(new OpenApiProcessor[0]));
                }
            }

            // 5. 执行处理器
            final List<OpenApiProcessor> processors = serviceContext.getProcessors();
            // 5.1 打印当前处理器顺序日志
            processors.stream().forEach(processor -> log.debug("{}的序号是{}", processor.getClass()
                    .getSimpleName(), processor.level()));
            // 5.2 开始执行处理器
            // 5.2.1 自动排序
            List<OpenApiProcessor> sortedProcessors = processors.stream().distinct().sorted()
                    .collect(Collectors.toList());
            processors.clear();
            processors.addAll(sortedProcessors);
            // 5.2.2 执行处理器
            executeProcessors(processors, serviceContext);
        } catch (Exception e) {
            invoke.handleException(e, serviceContext);
        }

    }

    /**
     * 单个返回对象
     *
     * @param serviceContext 上下文
     * @param invoke         接口
     */
    public void executeForSimple(OpenApiProcessorServiceContext<OpenApiOrder, OpenSingleResult> serviceContext, OpenApiProcessorServiceInvoke invoke) {
        try {
            // 1. 增加预处理器
            serviceContext.addProcessors(openApiPreLogEventProcessor, openApiCheckOrderProcessor, openSimpleApiProcessor, openApiFacadeExecuteProcessor);
            invoke.addPreProcessor(serviceContext);
            // 2. 增加业务处理器
            invoke.addProcessor(serviceContext);
            // 3. 增加后处理器
            invoke.addPostProcessor(serviceContext);
            serviceContext.addProcessors(openApiPostLogEventProcessor);

            // 4. Mock处理器替换
            if (profileConfig.isMock()) {
                if (ObjectUtil.isNull(ServiceTestMockContextThreadLocal.currentContext())) {
                    new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().build());
                }

                // 4.1 获取全部继承于Process的处理器
                List<OpenApiProcessor> beans = context.getBeansOfType(OpenApiProcessor.class);

                // 将被替换的Mock处理器 列表
                List<OpenApiProcessor> mockProcessors = Lists.newArrayList();
                // 将被移除的处理器 列表
                List<String> removeProcessorName = Lists.newArrayList();

                // 4.2 获取当前使用的处理器
                List<OpenApiProcessor> processors = serviceContext.getProcessors();
                processors.forEach(processor -> {
                    String processorName = processor.getClass().getSimpleName();
                    beans.stream()
                            // 4.2.1 过滤出包含Mock名的处理器
                            .filter(bean -> bean.getClass().getSimpleName().contains("Mock"))
                            // 4.2.2 把包含Mock名的处理器取出
                            .filter(bean -> bean.getClass().getSimpleName().replaceAll("Mock", "")
                                    .equalsIgnoreCase(processorName)).findAny().ifPresent(bean -> {
                                // 填充需要替换的Mock处理器
                                mockProcessors.add(bean);
                                // 填充需要移除的处理器
                                removeProcessorName.add(processorName);
                            });
                });

                // 4.3 从当前使用的处理器中剔除可被Mock替换的处理器
                processors.removeIf(processor -> CollUtil.contains(removeProcessorName, processor.getClass()
                        .getSimpleName()));
                if (CollUtil.isNotEmpty(mockProcessors)) {
                    serviceContext.addProcessors(mockProcessors.toArray(new OpenApiProcessor[0]));
                }
            }

            // 5. 执行处理器
            final List<OpenApiProcessor> processors = serviceContext.getProcessors();
            // 5.1 打印当前处理器顺序日志
            processors.stream().forEach(processor -> log.debug("{}的序号是{}", processor.getClass()
                    .getSimpleName(), processor.level()));
            // 5.2 开始执行处理器
            // 5.2.1 自动排序
            List<OpenApiProcessor> sortedProcessors = processors.stream().distinct().sorted()
                    .collect(Collectors.toList());
            processors.clear();
            processors.addAll(sortedProcessors);
            // 5.2.2 执行处理器
            executeProcessors(processors, serviceContext);
        } catch (Exception e) {
            invoke.handleException(e, serviceContext);
        }

    }

    /**
     * 集合返回对象
     *
     * @param serviceContext 上下文
     * @param invoke         接口
     */
    public void executeForList(OpenApiProcessorServiceContext<OpenApiOrder, OpenListResult> serviceContext, OpenApiProcessorServiceInvoke invoke) {
        try {
            // 1. 增加预处理器
            serviceContext.addProcessors(openApiPreLogEventProcessor, openApiCheckOrderProcessor, openSimpleApiProcessor, openApiFacadeExecuteProcessor);
            invoke.addPreProcessor(serviceContext);
            // 2. 增加业务处理器
            invoke.addProcessor(serviceContext);
            // 3. 增加后处理器
            invoke.addPostProcessor(serviceContext);
            serviceContext.addProcessors(openApiPostLogEventProcessor);

            // 4. Mock处理器替换
            if (profileConfig.isMock()) {
                if (ObjectUtil.isNull(ServiceTestMockContextThreadLocal.currentContext())) {
                    new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().build());
                }

                // 4.1 获取全部继承于Process的处理器
                List<OpenApiProcessor> beans = context.getBeansOfType(OpenApiProcessor.class);

                // 将被替换的Mock处理器 列表
                List<OpenApiProcessor> mockProcessors = Lists.newArrayList();
                // 将被移除的处理器 列表
                List<String> removeProcessorName = Lists.newArrayList();

                // 4.2 获取当前使用的处理器
                List<OpenApiProcessor> processors = serviceContext.getProcessors();
                processors.forEach(processor -> {
                    String processorName = processor.getClass().getSimpleName();
                    beans.stream()
                            // 4.2.1 过滤出包含Mock名的处理器
                            .filter(bean -> bean.getClass().getSimpleName().contains("Mock"))
                            // 4.2.2 把包含Mock名的处理器取出
                            .filter(bean -> bean.getClass().getSimpleName().replaceAll("Mock", "")
                                    .equalsIgnoreCase(processorName)).findAny().ifPresent(bean -> {
                                // 填充需要替换的Mock处理器
                                mockProcessors.add(bean);
                                // 填充需要移除的处理器
                                removeProcessorName.add(processorName);
                            });
                });

                // 4.3 从当前使用的处理器中剔除可被Mock替换的处理器
                processors.removeIf(processor -> CollUtil.contains(removeProcessorName, processor.getClass()
                        .getSimpleName()));
                if (CollUtil.isNotEmpty(mockProcessors)) {
                    serviceContext.addProcessors(mockProcessors.toArray(new OpenApiProcessor[0]));
                }
            }

            // 5. 执行处理器
            final List<OpenApiProcessor> processors = serviceContext.getProcessors();
            // 5.1 打印当前处理器顺序日志
            processors.stream().forEach(processor -> log.debug("{}的序号是{}", processor.getClass()
                    .getSimpleName(), processor.level()));
            // 5.2 开始执行处理器
            // 5.2.1 自动排序
            List<OpenApiProcessor> sortedProcessors = processors.stream().distinct().sorted()
                    .collect(Collectors.toList());
            processors.clear();
            processors.addAll(sortedProcessors);
            // 5.2.2 执行处理器
            executeProcessors(processors, serviceContext);
        } catch (Exception e) {
            invoke.handleException(e, serviceContext);
        }

    }

    /**
     * 分页返回对象
     *
     * @param serviceContext 上下文
     * @param invoke         接口
     */
    public void executeForPage(OpenApiProcessorServiceContext<OpenApiOrder, OpenPageResult> serviceContext, OpenApiProcessorServiceInvoke invoke) {
        try {
            // 1. 增加预处理器
            serviceContext.addProcessors(openApiPreLogEventProcessor, openApiCheckOrderProcessor, openSimpleApiProcessor, openApiFacadeExecuteProcessor);
            invoke.addPreProcessor(serviceContext);
            // 2. 增加业务处理器
            invoke.addProcessor(serviceContext);
            // 3. 增加后处理器
            invoke.addPostProcessor(serviceContext);
            serviceContext.addProcessors(openApiPostLogEventProcessor);

            // 4. Mock处理器替换
            if (profileConfig.isMock()) {
                if (ObjectUtil.isNull(ServiceTestMockContextThreadLocal.currentContext())) {
                    new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().build());
                }

                // 4.1 获取全部继承于Process的处理器
                List<OpenApiProcessor> beans = context.getBeansOfType(OpenApiProcessor.class);

                // 将被替换的Mock处理器 列表
                List<OpenApiProcessor> mockProcessors = Lists.newArrayList();
                // 将被移除的处理器 列表
                List<String> removeProcessorName = Lists.newArrayList();

                // 4.2 获取当前使用的处理器
                List<OpenApiProcessor> processors = serviceContext.getProcessors();
                processors.forEach(processor -> {
                    String processorName = processor.getClass().getSimpleName();
                    beans.stream()
                            // 4.2.1 过滤出包含Mock名的处理器
                            .filter(bean -> bean.getClass().getSimpleName().contains("Mock"))
                            // 4.2.2 把包含Mock名的处理器取出
                            .filter(bean -> bean.getClass().getSimpleName().replaceAll("Mock", "")
                                    .equalsIgnoreCase(processorName)).findAny().ifPresent(bean -> {
                                // 填充需要替换的Mock处理器
                                mockProcessors.add(bean);
                                // 填充需要移除的处理器
                                removeProcessorName.add(processorName);
                            });
                });

                // 4.3 从当前使用的处理器中剔除可被Mock替换的处理器
                processors.removeIf(processor -> CollUtil.contains(removeProcessorName, processor.getClass()
                        .getSimpleName()));
                if (CollUtil.isNotEmpty(mockProcessors)) {
                    serviceContext.addProcessors(mockProcessors.toArray(new OpenApiProcessor[0]));
                }
            }

            // 5. 执行处理器
            final List<OpenApiProcessor> processors = serviceContext.getProcessors();
            // 5.1 打印当前处理器顺序日志
            processors.stream().forEach(processor -> log.debug("{}的序号是{}", processor.getClass()
                    .getSimpleName(), processor.level()));
            // 5.2 开始执行处理器
            // 5.2.1 自动排序
            List<OpenApiProcessor> sortedProcessors = processors.stream().distinct().sorted()
                    .collect(Collectors.toList());
            processors.clear();
            processors.addAll(sortedProcessors);
            // 5.2.2 执行处理器
            executeProcessors(processors, serviceContext);
        } catch (Exception e) {
            invoke.handleException(e, serviceContext);
        }

    }

    /**
     * 领域模型的命令模式执行器
     *
     * @param serviceContext 上下文
     * @param invoke         接口
     */
    public void executeForCallBack(OpenApiProcessorServiceContext<OpenApiOrder, OpenSingleResult> serviceContext, OpenApiProcessorServiceInvoke invoke) {
        try {
            // 1. 增加预处理器
            serviceContext.addProcessors(openApiPreLogEventProcessor, openApiCallbackOrderCheckProcessor, openApiFillOrderEncryptProcessor,
                    openApiCallbackMethodTypeProcessor);
            // todo peigen 微信回调的问题，之后解决
            // serviceContext.addProcessors(openApiPreLogEventProcessor, openApiCallbackOrderCheckProcessor, openApiFillOrderEncryptProcessor,
            //         openApiCallbackMethodTypeProcessor, openApiCallbackBusinessTypeProcessor);
            invoke.addPreProcessor(serviceContext);
            // 2. 增加业务处理器
            invoke.addProcessor(serviceContext);
            // 3. 增加后处理器
            invoke.addPostProcessor(serviceContext);
            serviceContext.addProcessors(openApiPostLogEventProcessor);

            // 4. Mock处理器替换
            if (profileConfig.isMock()) {
                if (ObjectUtil.isNull(ServiceTestMockContextThreadLocal.currentContext())) {
                    new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().build());
                }

                // 4.1 获取全部继承于Process的处理器
                List<OpenApiProcessor> beans = context.getBeansOfType(OpenApiProcessor.class);

                // 将被替换的Mock处理器 列表
                List<OpenApiProcessor> mockProcessors = Lists.newArrayList();
                // 将被移除的处理器 列表
                List<String> removeProcessorName = Lists.newArrayList();

                // 4.2 获取当前使用的处理器
                List<OpenApiProcessor> processors = serviceContext.getProcessors();
                processors.forEach(processor -> {
                    String processorName = processor.getClass().getSimpleName();
                    beans.stream()
                            // 4.2.1 过滤出包含Mock名的处理器
                            .filter(bean -> bean.getClass().getSimpleName().contains("Mock"))
                            // 4.2.2 把包含Mock名的处理器取出
                            .filter(bean -> bean.getClass().getSimpleName().replaceAll("Mock", "")
                                    .equalsIgnoreCase(processorName)).findAny().ifPresent(bean -> {
                                // 填充需要替换的Mock处理器
                                mockProcessors.add(bean);
                                // 填充需要移除的处理器
                                removeProcessorName.add(processorName);
                            });
                });

                // 4.3 从当前使用的处理器中剔除可被Mock替换的处理器
                processors.removeIf(processor -> CollUtil.contains(removeProcessorName, processor.getClass()
                        .getSimpleName()));
                if (CollUtil.isNotEmpty(mockProcessors)) {
                    serviceContext.addProcessors(mockProcessors.toArray(new OpenApiProcessor[0]));
                }
            }

            // 5. 执行处理器
            final List<OpenApiProcessor> processors = serviceContext.getProcessors();
            // 5.1 打印当前处理器顺序日志
            processors.stream().forEach(processor -> log.debug("{}的序号是{}", processor.getClass()
                    .getSimpleName(), processor.level()));
            // 5.2 开始执行处理器
            // 5.2.1 自动排序
            List<OpenApiProcessor> sortedProcessors = processors.stream().distinct().sorted()
                    .collect(Collectors.toList());
            processors.clear();
            processors.addAll(sortedProcessors);
            // 5.2.2 执行处理器
            executeProcessors(processors, serviceContext);
        } catch (Exception e) {
            invoke.handleException(e, serviceContext);
        }

    }

    /**
     * 领域模型的查询模式执行器
     *
     * @param serviceContext 上下文
     * @param query          查询接口
     */
    public void query(ServiceQueryContext serviceContext, ServiceQuery query) {

        // 0. 打印[开始]日志
        long                 beginTime = System.currentTimeMillis();
        ServiceOrderBase     order     = serviceContext.getOrder();
        ServiceOrderLogEvent logEvent  = ServiceOrderLogEvent.builder().order(order).build();
        logEventHandler.eventPost(logEvent);

        try {
            // 1. 校验入参
            query.checkOrder(serviceContext);

            // 2. 服务调用
            query.query(serviceContext);

            // 3. 组装返回对象
            query.convert(serviceContext);

            // 4. 打印[结果]日志
            ServiceResultLogEvent resultLogEvent = ServiceResultLogEvent.builder().productCode(order.getProductCode())
                    .bizOrderNo(order.getBizOrderNo()).build();

            // 4.1 组装返回对象
            // 4.1.1 组装集合返回对象
            if (serviceContext.getResult() instanceof ListResult) {
                resultLogEvent.setListResult((ListResult<?>) serviceContext.getResult());
            }

            // 4.1.2 组装单个返回对象
            if (serviceContext.getResult() instanceof SingleResult) {
                resultLogEvent.setSingleResult((SingleResult<?>) serviceContext.getResult());
            }

            // 4.1.3 组装分页返回对象
            if (serviceContext.getResult() instanceof PageResult) {
                resultLogEvent.setPageResult((PageResult<?>) serviceContext.getResult());
            }

            logEventHandler.eventPost(resultLogEvent);
        } catch (Exception e) {
            query.handleException(e, serviceContext);
        }
    }

    void executeProcessors(List<OpenApiProcessor> processors, OpenApiProcessorServiceContext serviceContext) {
        StopWatch watch = serviceContext.getWatch();

        try {
            TranUtils.execute(new TranAnno().isolation(read_committed).policy(TranPolicy.required),
                    () -> processors.stream().filter(ObjectUtil::isNotNull).forEach(processor -> {
                        watch.start("执行处理器:" + processor.getClass().getSimpleName());
                        processor.execute(serviceContext);
                        watch.stop();
                    }));
        } catch (Throwable e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    protected void parseToken(OpenApiProcessorServiceContext serviceContext, OpenApiOrder order, ResultBase result) {
        if (StrUtil.isNotEmpty(order.getToken())) {
            result.setToken(order.getToken());
            return;
        }
        result.setToken(serviceContext.getToken());
    }

}